# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, QtSerialPort
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSerialPort import *
import threading
import inspect

def getCallFrame():
    return sys._getframe(3) if hasattr(sys, "_getframe") else None

def getCallFrameInfo():
    # get the call frame of the calling method
    frame = getCallFrame()

    try:
        # find the name of the first variable in the calling
        # function - which is hopefully the "self"
        codeobj = frame.f_code
        try:
            self_name = codeobj.co_varnames[0]
        except IndexError:
            return None

        # try to access the caller's "self"
        try:
            self_obj = frame.f_locals[self_name]
        except KeyError:
            return None

        # check if the calling function is really a method
        self_type = type(self_obj)
        func_name = codeobj.co_name

        # iterate through all classes in the MRO
        for cls in self_type.__mro__:
            # see if this class has a method with the name
            # we're looking for
            try:
                method = vars(cls)[func_name]
            except KeyError:
                continue

            # unwrap the method just in case there are any decorators
            try:
                method = inspect.unwrap(method)
            except ValueError:
                pass

            # see if this is the method that called us
            if getattr(method, '__code__', None) is codeobj:
                typeName = self_type.__name__
            else:
                typeName = 'unknow'

        # if we didn't find a matching method, return None
        info = [typeName, func_name, frame.f_code.co_filename, frame.f_lineno]
        # print(info)
        return info
    finally:
        # make sure to clean up the frame at the end to avoid ref cycles
        del frame

def putInfo(info:str='None'):
    fInfo = getCallFrameInfo()
    print('[{0}.{1}]{2}'.format(fInfo[0], fInfo[1], info))

def putThreadId(caller: str='None'):
    t = threading.currentThread()
    print('\n[class]{0}\n[call func]{1}\n[curThread]{2}\n[curThreadId]{3}\n'.format(caller, \
                                                                                    sys._getframe().f_back.f_code.co_name, \
                                                                                    t.getName(), \
                                                                                    t.ident))

def putFuncArg(arg):
    print('\n[file]{0}\n[line]{1}\n[call func]{2}\n[input arg]'.format(sys._getframe(1).f_code.co_filename, \
                                                                       sys._getframe().f_back.f_lineno, \
                                                                       sys._getframe().f_back.f_code.co_name), arg)
